package org.framework.edge.builder.application.impl;

import lombok.extern.slf4j.Slf4j;
import org.framework.edge.builder.application.command.docker.repository.DockerRepositoryBackupsCommand;
import org.framework.edge.builder.application.command.docker.repository.DockerRepositoryQueryListCommand;
import org.framework.edge.builder.application.dto.DockerRepositoryDTO;
import org.framework.edge.builder.docker.DockerRuntime;
import org.framework.edge.builder.domain.model.docker.images.DockerImages;
import org.framework.edge.builder.domain.model.docker.images.DockerImagesRepository;
import org.framework.edge.builder.domain.model.docker.repository.DockerRepository;
import org.framework.edge.builder.domain.model.docker.repository.DockerRepositoryRepository;
import org.framework.edge.builder.domain.model.docker.repository.backup.record.DockerRepositoryBackupRecord;
import org.framework.edge.builder.domain.model.docker.repository.backup.record.DockerRepositoryBackupRecordRepository;
import org.wu.framework.core.exception.RuntimeExceptionFactory;
import org.wu.framework.lazy.orm.web.plus.stereotype.LazyApplication;
import org.framework.edge.builder.application.DockerRepositoryBackupApplication;
import org.springframework.web.bind.annotation.*;
import org.wu.framework.web.response.Result;
import org.wu.framework.web.response.ResultFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.framework.edge.builder.domain.model.docker.repository.backup.DockerRepositoryBackup;
import org.framework.edge.builder.application.command.docker.repository.backup.DockerRepositoryBackupRemoveCommand;
import org.framework.edge.builder.application.command.docker.repository.backup.DockerRepositoryBackupStoryCommand;
import org.framework.edge.builder.application.command.docker.repository.backup.DockerRepositoryBackupUpdateCommand;
import org.framework.edge.builder.application.command.docker.repository.backup.DockerRepositoryBackupQueryListCommand;
import org.framework.edge.builder.application.command.docker.repository.backup.DockerRepositoryBackupQueryOneCommand;
import org.framework.edge.builder.application.assembler.DockerRepositoryBackupDTOAssembler;
import org.framework.edge.builder.application.dto.DockerRepositoryBackupDTO;

import java.util.UUID;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import java.util.stream.Collectors;

import jakarta.annotation.Resource;
import org.framework.edge.builder.domain.model.docker.repository.backup.DockerRepositoryBackupRepository;

import java.util.List;

import org.wu.framework.lazy.orm.database.lambda.domain.LazyPage;
import org.framework.edge.builder.application.command.docker.repository.backup.DockerRepositoryBackupExcelExport;
import org.framework.edge.builder.application.command.docker.repository.backup.DockerRepositoryBackupExcelImport;

/**
 * describe Docker仓库备份
 *
 * @author Jia wei Wu
 * @date 2025/07/10 08:18 晚上
 * @see org.wu.framework.lazy.orm.core.persistence.reverse.lazy.ddd.DefaultDDDLazyApplicationImpl
 **/
@Slf4j
@LazyApplication
public class DockerRepositoryBackupApplicationImpl implements DockerRepositoryBackupApplication {

    @Resource
    DockerRepositoryBackupRepository dockerRepositoryBackupRepository;

    @Resource
    DockerImagesRepository dockerImagesRepository;

    @Resource
    DockerRepositoryRepository DockerRepositoryRepository;

    @Resource
    DockerRepositoryBackupRecordRepository dockerRepositoryBackupRecordRepository;


    @Resource
    DockerRuntime dockerRuntime;

    /**
     * describe 新增Docker仓库备份
     *
     * @param dockerRepositoryBackupStoryCommand 新增Docker仓库备份
     * @return {@link Result<DockerRepositoryBackup>} Docker仓库备份新增后领域对象
     * @author Jia wei Wu
     * @date 2025/07/10 08:18 晚上
     **/

    @Override
    public Result<DockerRepositoryBackup> story(DockerRepositoryBackupStoryCommand dockerRepositoryBackupStoryCommand) {
        DockerRepositoryBackup dockerRepositoryBackup = DockerRepositoryBackupDTOAssembler.INSTANCE.toDockerRepositoryBackup(dockerRepositoryBackupStoryCommand);
        return dockerRepositoryBackupRepository.story(dockerRepositoryBackup);
    }

    /**
     * describe 批量新增Docker仓库备份
     *
     * @param dockerRepositoryBackupStoryCommandList 批量新增Docker仓库备份
     * @return {@link Result<List<DockerRepositoryBackup>>} Docker仓库备份新增后领域对象集合
     * @author Jia wei Wu
     * @date 2025/07/10 08:18 晚上
     **/

    @Override
    public Result<List<DockerRepositoryBackup>> batchStory(List<DockerRepositoryBackupStoryCommand> dockerRepositoryBackupStoryCommandList) {
        List<DockerRepositoryBackup> dockerRepositoryBackupList = dockerRepositoryBackupStoryCommandList.stream().map(DockerRepositoryBackupDTOAssembler.INSTANCE::toDockerRepositoryBackup).collect(Collectors.toList());
        return dockerRepositoryBackupRepository.batchStory(dockerRepositoryBackupList);
    }

    /**
     * describe 更新Docker仓库备份
     *
     * @param dockerRepositoryBackupUpdateCommand 更新Docker仓库备份
     * @return {@link Result<DockerRepositoryBackup>} Docker仓库备份领域对象
     * @author Jia wei Wu
     * @date 2025/07/10 08:18 晚上
     **/

    @Override
    public Result<DockerRepositoryBackup> updateOne(DockerRepositoryBackupUpdateCommand dockerRepositoryBackupUpdateCommand) {
        DockerRepositoryBackup dockerRepositoryBackup = DockerRepositoryBackupDTOAssembler.INSTANCE.toDockerRepositoryBackup(dockerRepositoryBackupUpdateCommand);
        return dockerRepositoryBackupRepository.story(dockerRepositoryBackup);
    }

    /**
     * describe 查询单个Docker仓库备份
     *
     * @param dockerRepositoryBackupQueryOneCommand 查询单个Docker仓库备份
     * @return {@link Result<DockerRepositoryBackupDTO>} Docker仓库备份DTO对象
     * @author Jia wei Wu
     * @date 2025/07/10 08:18 晚上
     **/

    @Override
    public Result<DockerRepositoryBackupDTO> findOne(DockerRepositoryBackupQueryOneCommand dockerRepositoryBackupQueryOneCommand) {
        DockerRepositoryBackup dockerRepositoryBackup = DockerRepositoryBackupDTOAssembler.INSTANCE.toDockerRepositoryBackup(dockerRepositoryBackupQueryOneCommand);
        return dockerRepositoryBackupRepository.findOne(dockerRepositoryBackup).convert(DockerRepositoryBackupDTOAssembler.INSTANCE::fromDockerRepositoryBackup);
    }

    /**
     * describe 查询多个Docker仓库备份
     *
     * @param dockerRepositoryBackupQueryListCommand 查询多个Docker仓库备份
     * @return {@link Result<List<DockerRepositoryBackupDTO>>} Docker仓库备份DTO对象
     * @author Jia wei Wu
     * @date 2025/07/10 08:18 晚上
     **/

    @Override
    public Result<List<DockerRepositoryBackupDTO>> findList(DockerRepositoryBackupQueryListCommand dockerRepositoryBackupQueryListCommand) {
        DockerRepositoryBackup dockerRepositoryBackup = DockerRepositoryBackupDTOAssembler.INSTANCE.toDockerRepositoryBackup(dockerRepositoryBackupQueryListCommand);
        return dockerRepositoryBackupRepository.findList(dockerRepositoryBackup).convert(dockerRepositoryBackups -> dockerRepositoryBackups.stream().map(DockerRepositoryBackupDTOAssembler.INSTANCE::fromDockerRepositoryBackup).collect(Collectors.toList()));
    }

    /**
     * describe 分页查询多个Docker仓库备份
     *
     * @param dockerRepositoryBackupQueryListCommand 分页查询多个Docker仓库备份
     * @return {@link Result<LazyPage<DockerRepositoryBackupDTO>>} 分页Docker仓库备份DTO对象
     * @author Jia wei Wu
     * @date 2025/07/10 08:18 晚上
     **/

    @Override
    public Result<LazyPage<DockerRepositoryBackupDTO>> findPage(int size, int current, DockerRepositoryBackupQueryListCommand dockerRepositoryBackupQueryListCommand) {
        DockerRepositoryBackup dockerRepositoryBackup = DockerRepositoryBackupDTOAssembler.INSTANCE.toDockerRepositoryBackup(dockerRepositoryBackupQueryListCommand);
        return dockerRepositoryBackupRepository.findPage(size, current, dockerRepositoryBackup).convert(page -> page.convert(DockerRepositoryBackupDTOAssembler.INSTANCE::fromDockerRepositoryBackup));
    }

    /**
     * describe 删除Docker仓库备份
     *
     * @param dockerRepositoryBackupRemoveCommand 删除Docker仓库备份
     * @return {@link Result<DockerRepositoryBackup>} Docker仓库备份
     * @author Jia wei Wu
     * @date 2025/07/10 08:18 晚上
     **/

    @Override
    public Result<DockerRepositoryBackup> remove(DockerRepositoryBackupRemoveCommand dockerRepositoryBackupRemoveCommand) {
        DockerRepositoryBackup dockerRepositoryBackup = DockerRepositoryBackupDTOAssembler.INSTANCE.toDockerRepositoryBackup(dockerRepositoryBackupRemoveCommand);
        return dockerRepositoryBackupRepository.remove(dockerRepositoryBackup);
    }

    /**
     * describe 导出Docker仓库备份
     *
     * @param dockerRepositoryBackupQueryListCommand 导出Docker仓库备份
     * @return {@link List<DockerRepositoryBackupExcelExport>} Docker仓库备份
     * @author Jia wei Wu
     * @date 2025/07/10 08:18 晚上
     **/

    @Override
    public List<DockerRepositoryBackupExcelExport> exportExcel(DockerRepositoryBackupQueryListCommand dockerRepositoryBackupQueryListCommand) {
        DockerRepositoryBackup dockerRepositoryBackup = DockerRepositoryBackupDTOAssembler.INSTANCE.toDockerRepositoryBackup(dockerRepositoryBackupQueryListCommand);
        return dockerRepositoryBackupRepository.findList(dockerRepositoryBackup).applyOther(dockerRepositoryBackups -> dockerRepositoryBackups.stream().map(DockerRepositoryBackupDTOAssembler.INSTANCE::fromDockerRepositoryBackupToExcelExport).collect(Collectors.toList()));
    }

    /**
     * describe 导入Docker仓库备份
     *
     * @param dockerRepositoryBackupExcelImportList 导入Docker仓库备份
     * @return {@link Result<DockerRepositoryBackupExcelImport>} Docker仓库备份
     * @author Jia wei Wu
     * @date 2025/07/10 08:18 晚上
     **/

    @Override
    public Result<List<DockerRepositoryBackupExcelImport>> importExcel(List<DockerRepositoryBackupExcelImport> dockerRepositoryBackupExcelImportList) {
        List<DockerRepositoryBackup> dockerRepositoryBackupList = dockerRepositoryBackupExcelImportList.stream().map(DockerRepositoryBackupDTOAssembler.INSTANCE::toDockerRepositoryBackup).collect(Collectors.toList());
        dockerRepositoryBackupRepository.batchStory(dockerRepositoryBackupList);
        return ResultFactory.successOf(dockerRepositoryBackupExcelImportList);
    }

    /**
     * 仓库备份
     *
     * @param dockerRepositoryBackupsCommand 备份信息
     * @return
     */
    @Override
    public Result<DockerRepository> backups(DockerRepositoryBackupsCommand dockerRepositoryBackupsCommand) {

        // 确定仓库是否存在
        String sourceRepositoryId = dockerRepositoryBackupsCommand.getSourceRepositoryId();
        String tagRepositoryId = dockerRepositoryBackupsCommand.getTagRepositoryId();
        DockerRepository dockerRepositoryQuery = new DockerRepository();
        dockerRepositoryQuery.setIsDeleted(false);
        ConcurrentMap<String, DockerRepository> dockerRepositoryConcurrentMap =
                DockerRepositoryRepository
                        .findList(dockerRepositoryQuery)
                        .applyOther(dockerRepositories ->
                                dockerRepositories.stream().collect(Collectors.toConcurrentMap(DockerRepository::getId, Function.identity(), (A, B) -> A))
                        );
        if (!dockerRepositoryConcurrentMap.containsKey(sourceRepositoryId)) {
            RuntimeExceptionFactory.of("仓库:%s 不存在", sourceRepositoryId);
        }
        if (!dockerRepositoryConcurrentMap.containsKey(tagRepositoryId)) {
            RuntimeExceptionFactory.of("仓库:%s 不存在", tagRepositoryId);
        }
        DockerRepository sourceDockerRepository = dockerRepositoryConcurrentMap.get(sourceRepositoryId);
        String sourceUrl = sourceDockerRepository.getUrl();
        DockerRepository tagDockerRepository = dockerRepositoryConcurrentMap.get(tagRepositoryId);
        String tagUrl = tagDockerRepository.getUrl();
        // 查询镜像
        DockerImages dockerImages = new DockerImages();
        dockerImages.setIsDeleted(false);
        dockerImages.setRepositoryId(sourceRepositoryId);


        dockerImagesRepository.findList(dockerImages).accept(dockerImagesList -> {

            List<DockerImages> sourceImagesList = dockerImagesList.stream().toList();
            String backupId = UUID.randomUUID().toString();
            // 备份记录存储
            DockerRepositoryBackupStoryCommand dockerRepositoryBackupStoryCommand = new DockerRepositoryBackupStoryCommand();
            dockerRepositoryBackupStoryCommand.setSourceRepositoryId(sourceRepositoryId);
            dockerRepositoryBackupStoryCommand.setTagRepositoryId(tagRepositoryId);
            dockerRepositoryBackupStoryCommand.setId(backupId);
            dockerRepositoryBackupStoryCommand.setTotalImageNum(sourceImagesList.size());
            dockerRepositoryBackupStoryCommand.setIsDeleted(false);

            this.story(dockerRepositoryBackupStoryCommand);
            log.info("计划备份镜像仓库数量:{}", sourceImagesList.size());
            int backupSuccessCount = 0;
            for (int i = 0; i < sourceImagesList.size(); i++) {
                log.info("备份第:{}个镜像,总镜像数量:{}", i + 1, sourceImagesList.size());
                boolean dockerCommandSuccess = false;
                DockerImages images = sourceImagesList.get(i);
                // 镜像 pull
                String name = images.getName();
                String version = images.getVersion();
                String imageName = name + ":" + version;
                dockerCommandSuccess = dockerRuntime.pull(imageName).isSuccess();
                // 镜像 tag
                // 替换仓库url
                String newName = name.replace(sourceUrl, tagUrl);
                String newImageName = imageName.replace(sourceUrl, tagUrl);
                String newImageId = tagRepositoryId + newName;
                dockerCommandSuccess = dockerRuntime.tag(imageName, newImageName).isSuccess();
                // 镜像 push
                dockerCommandSuccess = dockerRuntime.push(newImageName).isSuccess();

                DockerImages tagDockerImages = new DockerImages();
                tagDockerImages.setRepositoryId(tagRepositoryId);
                tagDockerImages.setId(newImageId);
                tagDockerImages.setName(newName);
                tagDockerImages.setVersion(version);
                tagDockerImages.setIsDeleted(false);
                // 存储代理后的镜像
                dockerImagesRepository.story(tagDockerImages);


                // 存储备份记录
                DockerRepositoryBackupRecord dockerRepositoryBackupRecord = new DockerRepositoryBackupRecord();
                dockerRepositoryBackupRecord.setBackupId(backupId);
                dockerRepositoryBackupRecord.setSourceRepositoryId(sourceRepositoryId);
                dockerRepositoryBackupRecord.setSourceImageName(name);
                dockerRepositoryBackupRecord.setSourceImageVersion(version);

                dockerRepositoryBackupRecord.setTagRepositoryId(tagRepositoryId);
                dockerRepositoryBackupRecord.setTargetImageName(newImageName);
                dockerRepositoryBackupRecord.setTargetImageVersion(version);
                dockerRepositoryBackupRecord.setIsDeleted(false);
                if (dockerCommandSuccess) {
                    backupSuccessCount++;
                    dockerRepositoryBackupRecord.setBackupSuccess(true);
                    dockerRepositoryBackupRecordRepository.story(dockerRepositoryBackupRecord);
                } else {
                    dockerRepositoryBackupRecord.setBackupSuccess(false);
                    dockerRepositoryBackupRecordRepository.story(dockerRepositoryBackupRecord);
                }

                dockerRepositoryBackupStoryCommand.setBackupImageNum(backupSuccessCount);
                // 更新备份成功数量
                this.story(dockerRepositoryBackupStoryCommand);
            }
        });


        return ResultFactory.successOf();
    }
}